[Knowledge bases for Amazon Bedrock] 居酒屋の案内をするナレッジベースをCDKでデプロイしてみました
1 はじめに
CX事業本部製造ビジネステクノロジー部の平内(SIN)です。
Knowledge bases for Amazon Bedrockを使用すると、非常に簡単にRAGを構築することができまが、今回は、これを更に手軽にデプロイ出来るようにとCDK化してみました。
サンプルとして作成したナレッジベースは、架空の居酒屋の案内をするものです。 最初に、動作している様子をご確認ください。
2 データ
架空の居酒屋のデータとして用意したのは、以下の2つです。
- お店の案内 izakaya_guidance.pdf
- メニュー izakaya_menu.txt
どちらも、GPT-4oに作成してもらいました。
架空の居酒屋の説明文を考えてください。 架空の居酒屋は、焼き鳥とおでんがおすすめで、その他に、ご飯もの、魚料理、サイドメニューもあります 各メニューは、リーズナブルで、250円から600円の範囲となっています 説明文には、以下を含めてください。 1. 営業時間 2. お休み 3. お店の特徴(200文字程度) 4. アクセス 5. その他注意事項
架空の居酒屋のメニューを100種類考えてください メニューは、一覧形式で出力してください 各メニューには、メニュー番号、名前、価格、説明、分類を含めてください 分類は、「ご飯もの」「焼き鳥」「おでん」「魚料理」「サイドメニュー」の5種類です 各メニューの説明は、それぞれ独創的で、面白みのあるものにしてください 価格は、250円から600円の範囲としてください
3 Pinecone
Pineconeのインデックスデータベースは、手動で作成しています。 設定値は、以下の通りで、作成後にHOST(エンドポイント)をCDKデプロイ時に使用できるようコピーしておきます。
- 名前: kb-izakaya
- Dimensions: 1,536
- Metric: Cosine
- Capacity mode: SERVERRESS
- Region: us-east-1
なお、AWSから接続するためには、PineconeのAPIキーをSecretManagerに保存する必要があります。
シークレットのARNもCDKデプロイ時に必要となります。
4 CDK
(1) コード
CDKの主なコードは、以下のとおりです。
データソース用のS3バケット、必要なRole そして、Pineconeをストレージとするナレッジベースとデータソースが定義されています。
lib/amazon-bedrock-kb-izakaya-stack.ts
import * as cdk from "aws-cdk-lib"; import { Construct } from "constructs"; import { CfnOutput, RemovalPolicy } from "aws-cdk-lib"; import { aws_iam, aws_s3, aws_bedrock } from "aws-cdk-lib"; export class AmazonBedrockKbIzakayaStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); const tag = "kb-izakaya"; const bucketName = `${tag}-${this.account}`; const embeddingModelArn = this.node.tryGetContext("embeddingModelArn"); const pineconeEndpoint = this.node.tryGetContext("pineconeEndpoint"); const pineconeSecretArn = this.node.tryGetContext("pineconeSecretArn"); // S3 bucket for the data source const dataSourceBucket = new aws_s3.Bucket(this, "DataSourceBucket", { bucketName: bucketName, removalPolicy: RemovalPolicy.DESTROY, }); // Role for the knowledge base const knowledgeBaseRole = new aws_iam.Role(this, `KnowledgeBaseRole`, { roleName: `${tag}_role`, assumedBy: new aws_iam.ServicePrincipal("bedrock.amazonaws.com"), inlinePolicies: { inlinePolicy1: new aws_iam.PolicyDocument({ statements: [ new aws_iam.PolicyStatement({ resources: [pineconeSecretArn], actions: ["secretsmanager:GetSecretValue"], }), new aws_iam.PolicyStatement({ resources: [embeddingModelArn], actions: ["bedrock:InvokeModel"], }), new aws_iam.PolicyStatement({ resources: [ `arn:aws:s3:::${bucketName}`, `arn:aws:s3:::${bucketName}/*`, ], actions: ["s3:ListBucket", "s3:GetObject"], }), ], }), }, }); // knowledge Base const knowledgeBase = new aws_bedrock.CfnKnowledgeBase( this, "KnowledgeBase", { knowledgeBaseConfiguration: { type: "VECTOR", vectorKnowledgeBaseConfiguration: { embeddingModelArn: embeddingModelArn, }, }, name: tag, roleArn: knowledgeBaseRole.roleArn, storageConfiguration: { type: "PINECONE", pineconeConfiguration: { connectionString: pineconeEndpoint, credentialsSecretArn: pineconeSecretArn, fieldMapping: { metadataField: "metadata", textField: "text", }, }, }, description: "IZAKAYA knowledge base", } ); // data source new aws_bedrock.CfnDataSource(this, "BedrockKnowledgeBaseDataStore", { name: `${tag}-data-source`, knowledgeBaseId: knowledgeBase.ref, dataSourceConfiguration: { s3Configuration: { bucketArn: dataSourceBucket.bucketArn, }, type: "S3", }, }); // Output the AWS CLI command to upload a file to the S3 bucket const dataSourceFiles: string[] = [ "izakaya_menu.txt", "izakaya_guidance.pdf", ]; dataSourceFiles.forEach((dataSourceFile) => { const uploadCommand = `aws s3 cp assets/${dataSourceFile} s3://${bucketName}/${dataSourceFile}`; new CfnOutput(this, `UploadCommand_${dataSourceFile}`, { value: uploadCommand, description: `AWS CLI command to upload a file to the S3 bucket`, }); }); } }
(2) デプロイ
CDKのコードは、Githubにあり、以下の手順でデプロイできます。
https://github.com/furuya02/amazon-bedrock-kb-izakaya
% git clone https://github.com/furuya02/amazon-bedrock-kb-izakaya.git % cd amazon-bedrock-kb-izakaya % npm install
cdk.jsonにPineconeに関する設定がありますので、エンドポイント及びシークレットのARNを編集します。
"context": { "pineconeEndpoint": "https://xxxxxxx.pinecone.io", "pineconeSecretArn": "arn:aws:secretsmanager:us-east-1:xxxxxxxx",
CDKデプロイは、以下のとおりです。
% export AWS_DEFAULT_REGION=us-east-1 % npx cdk deploy
Githubリポジトリの、assetsフォルダに今回使用したデータがありますので、作成されたバケットにアップロード してください。
% aws s3 cp assets/izakaya_guidance.pdf s3://kb-izakaya-xxxxxxxx/izakaya_guidance.pdf % aws s3 cp assets/izakaya_menu.txt s3://kb-izakaya-xxxxxxxx/izakaya_menu.txt
5 同期
CDKデプロイ及び、データのアップロード後、「同期」することで、データは、ベクトル化され保存されます。
Pinecodeのコンソールでは、ベクトル化されたデータを確認することもできます。
6 動作確認
テストには、Anthropic Claude v2.1を使用しました。
アップロードしたデータを元に、質問に答えていることが確認できます
7 最後に
今回は、PineconeをストレージとしたKnowledge bases for Amazon BedrockをCDKで作成してみました。
作業中少し戸惑ったのは、以下の2点でした。
(1) Embedding ModelのARN
コンソール上には、ARNが出てこないので、CLIで列挙して確認しました。
% export AWS_DEFAULT_REGION=us-east-1 % % aws bedrock list-foundation-models | grep modelArn | grep titan-embed-text "modelArn": "arn:aws:bedrock:us-east-1::foundation-model/amazon.titan-embed-text-v1:2:8k", "modelArn": "arn:aws:bedrock:us-east-1::foundation-model/amazon.titan-embed-text-v1", "modelArn": "arn:aws:bedrock:us-east-1::foundation-model/amazon.titan-embed-text-v2:0:8k", "modelArn": "arn:aws:bedrock:us-east-1::foundation-model/amazon.titan-embed-text-v2:0",
(2) 依存関係
最後までよく分からなかったのですが、ロールを先に作成するように、明示的に指定しないと、デプロイに失敗してました。
knowledgeBase.node.addDependency(knowledgeBaseRole);
「(2) 依存関係」 の問題は、Roleの作成時に addPolidy() を使用していたことが原因でした。 aws_iam.Role.inlinePolicies に修正することでaddDependency()は、必要なくなりました。
addPolidy()は、CDK上別のオブジェクトとなるため、タイミングによって、CfnKnowledgeBaseの生成時にポリシー不足が指摘されていたようです。
CfnKnowledgeBaseのプロパティ roleArnは、生成時に検証されているようなので注意が必要のようです。
やまたつさんに教えて頂きました。m(_._)m
元々、Knowledge bases for Amazon Bedrockの構築は、非常に簡単ですが、 ランニングコストが比較的低いPineconeを使用したものをCDK化しておくことで、更に手軽に利用できるのでは?と妄想しています。
8 参考にさせて頂いたリンク
Set up a vector index for your knowledge base in a supported vector store
AWS Marketplace の Pinecone を Amazon Bedrock のナレッジベースとして利用する